package com.software610;

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.Collections;
import java.util.Vector;

public class GPProject {

	private static Vector<GenSet> genSetFunctions = new Vector<GenSet>();
	private static Vector<DataSet> trainingData = new Vector<DataSet>();
	private static final int dataSetMax = 10;
	private static final int dataSetStarting = -5;
	private static final String x0Value = "X*X-2/2";
	private static enum State {START, NUM, ADD, SUB, MUL, DIV};

	public static void init()
	{
		//load initial program sets.
		loadSets();
		//initialize the Training data
		generateSetData(x0Value, trainingData);
	}

	public static void loadSets() //maybe create something to randomly generate these? ..maybe the same thing that does the X-over/mutation
	{
		genSetFunctions.add(new GenSet(0,"2*X+5/4", new BigDecimal(0)));
		genSetFunctions.add(new GenSet(0,"4+X*5*X-4", new BigDecimal(0)));
		genSetFunctions.add(new GenSet(0,"X*X-9/6", new BigDecimal(0)));
	}

	public static Vector<DataSet> generateSetData(String function) {
		return(generateSetData(function, new Vector<DataSet>()));
	}

	public static Vector<DataSet> generateSetData(String function, Vector<DataSet> result)
	{
		for (int x = 0; x < dataSetMax; x++) {
			State state = State.START;
			int x0 = dataSetStarting + x;
			BigDecimal ttl = new BigDecimal(0);

			for (int f = 0; f < function.length(); f++) {
				String fVal = function.substring(f, (f + 1)).replaceAll("X", String.valueOf(x0));
				if (state == State.START) {
					ttl = ttl.add(new BigDecimal(fVal));
				} else if (state == State.ADD) {
					ttl = ttl.add(new BigDecimal(fVal));
				} else if (state == State.SUB) {
					ttl = ttl.subtract(new BigDecimal(fVal));
				} else if (state == State.MUL) {
					ttl = ttl.multiply(new BigDecimal(fVal));
				} else if (state == State.DIV) {
					ttl = ttl.divide(new BigDecimal(fVal), MathContext.DECIMAL64);
				}

				if (fVal.equalsIgnoreCase("+")) {
					state = State.ADD;
				} else if (fVal.equalsIgnoreCase("-")){
					state = State.SUB;
				} else if (fVal.equalsIgnoreCase("*")){
					state = State.MUL;
				} else if (fVal.equalsIgnoreCase("/")){
					state = State.DIV;
				} else {
					state = State.NUM;
				}
			}
			result.add(new DataSet(new BigDecimal(x0), ttl));		
		}
		return(result);
	}

	public static BigDecimal compareDataSets(Vector<DataSet> setData)
	{
		BigDecimal result = new BigDecimal(0);
		
		for (int d = 0; d < setData.size(); d++) {
			result = result.add(setData.get(d).getY().subtract(trainingData.get(d).getY()).abs());
		}
		
		return (result);
	}

	public static void main(String[] args) 
	{
		init();
		for (int y = 0; y < trainingData.size(); y++) {
			System.out.println(trainingData.get(y).getX() + "~" + trainingData.get(y).getY());
		}
		//compareSet to training Data
		for (int c = 0; c < genSetFunctions.size(); c++) {
			Vector<DataSet> cSets  = generateSetData(genSetFunctions.get(c).getFunction());
			BigDecimal delta = compareDataSets(cSets);
			genSetFunctions.get(c).setTrainingDelta(delta);
/*
//below is strickly for testing that cSets is populating correctly.
			System.out.println("Xxxxxxxxxx " + genSetFunctions.get(c).getFunction() + " xxxxxxxxxxX");
			for (int x = 0; x < cSets.size(); x++) {
				System.out.println(cSets.get(x).getX() + "~" + cSets.get(x).getY());
			}
			System.out.println("Xxxxxxxxxx " + genSetFunctions.get(c).getTrainingDelta() + " xxxxxxxxxxX");
//end of test
*/
		}

		//print out setData
		System.out.println("Xxxxx Sets Generation " + genSetFunctions.get(0).getGeneration() + " xxxxX");
		Collections.sort(genSetFunctions);
		for (int s = 0; s < genSetFunctions.size(); s++) {
			System.out.println(genSetFunctions.get(s).getFunction() + "    :    " + genSetFunctions.get(s).getTrainingDelta());
		}
	}

}
